package top.lingkang.finalsql.ui;

import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import top.lingkang.finalsql.config.SqlConfig;
import top.lingkang.finalsql.dev.FinalSqlDevDataSource;
import top.lingkang.finalsql.sql.FinalSql;
import top.lingkang.finalsql.sql.core.FinalSqlManage;

import java.io.*;
import java.net.URL;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

/**
 * @author lingkang
 * Created by 2022/11/7
 */
public class GenerateUIController implements Initializable {
    @FXML
    private ComboBox<String> driverName, comboBoxBuild;
    @FXML
    private Button selectDir, build;
    @FXML
    private TextField pack, url, username, password, ignoreTablePrefix, ignoreTable;
    @FXML
    private CheckBox cover;

    private GenerateBuild generateBuild;
    public File file = new File(System.getProperty("java.io.tmpdir") + File.separator + "final-sql-ui.properties");
    public Properties conf = new Properties();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        try {
            if (file.exists()) {
                conf.load(new FileInputStream(file));
                url.setText(conf.getProperty("url"));
                password.setText(conf.getProperty("password"));
                username.setText(conf.getProperty("username"));
                ignoreTablePrefix.setText(conf.getProperty("ignoreTablePrefix"));
                ignoreTable.setText(conf.getProperty("ignoreTable"));
                cover.setSelected(Boolean.parseBoolean(conf.getProperty("cover", "true")));
            } else
                file.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("配置文件路径" + file.getAbsolutePath() + "\n所在目录：" + file.getParentFile().getAbsolutePath());
        driverName.setItems(FXCollections.observableArrayList(
                "com.mysql.jdbc.Driver",
                "com.mysql.cj.jdbc.Driver",
                "org.sqlite.JDBC"
        ));
        driverName.getSelectionModel().select(Integer.parseInt(conf.getProperty("driverIndex", "0")));
        comboBoxBuild.setItems(FXCollections.observableArrayList(
                "mysql5.7 生成器",
                "sqlite4 生成器",
                "postgre 生成器(未开发)"
        ));
        comboBoxBuild.getSelectionModel().select(Integer.parseInt(conf.getProperty("buildIndex", "0")));
        driverName.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            int index = driverName.getSelectionModel().getSelectedIndex();
            if (index >= 0 && index <= 1) {
                comboBoxBuild.getSelectionModel().select(0);
            }
            conf.setProperty("driverIndex", index + "");
        });
        comboBoxBuild.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            conf.setProperty("buildIndex", comboBoxBuild.getSelectionModel().getSelectedIndex() + "");
        });
        cover.selectedProperty().addListener((observable, oldValue, newValue) -> {
            conf.setProperty("cover", newValue.toString());
        });

        pack.setText(conf.getProperty("packageDir", ""));
        selectDir.setOnMouseClicked(event -> {
            File pFile = new File(GenerateUtils.getBasePath());
            if (!isBlank(pack.getText()) && new File(pack.getText()).isDirectory())
                pFile = new File(pack.getText());
            DirectoryChooser directoryChooser = new DirectoryChooser();
            directoryChooser.setInitialDirectory(pFile);
            directoryChooser.setTitle("选择实体类目录");
            File file = directoryChooser.showDialog(selectDir.getScene().getWindow());
            if (file != null && file.isDirectory()) {
                pack.setText(file.getAbsolutePath());
                conf.setProperty("packageDir", file.getAbsolutePath());
            } else {
                ToastUtil.toast("输出包路径错误", selectDir.getScene().getWindow());
            }
        });

        build.setOnMouseClicked(event -> {
            if (isBlank(pack.getText())) {
                ToastUtil.toast("输出包路径不能为空", selectDir.getScene().getWindow());
                pack.requestFocus();
                return;
            }
            if (!new File(pack.getText()).isDirectory()) {
                ToastUtil.toast("输出包路径不是一个文件目录", selectDir.getScene().getWindow());
                pack.requestFocus();
                return;
            }
            if (!new File(pack.getText()).exists()) {
                ToastUtil.toast("输出包路径是一个不存在的文件目录", selectDir.getScene().getWindow());
                pack.requestFocus();
                return;
            }
            int selectedIndex = driverName.getSelectionModel().getSelectedIndex();
            FinalSql finalSql = null;
            try {
                finalSql = getFinalSql();
                finalSql.beginTransaction();
                if (comboBoxBuild.getSelectionModel().getSelectedIndex() == 0) {
                    if (selectedIndex != 0 && selectedIndex != 1)
                        throw new RuntimeException("数据库连接驱动与生成实现不匹配，例如：mysql的生成器无法在sqlite数据库驱动中使用");
                    generateBuild = new GenerateBuildMysql();
                }

                if (comboBoxBuild.getSelectionModel().getSelectedIndex() == 1) {
                    if (selectedIndex != 2)
                        throw new RuntimeException("数据库连接驱动与生成实现不匹配，例如：mysql的生成器无法在sqlite数据库驱动中使用");
                    generateBuild = new GenerateBuildSqlite3();
                }
                if (generateBuild == null) {
                    ToastUtil.toast("未识别的生成实现", selectDir.getScene().getWindow());
                    return;
                }
                GenerateProperties properties = new GenerateProperties();
                properties.setCover(cover.isSelected());
                properties.setOutDir(pack.getText());
                properties.setIgnoreTablePrefix(ignoreTablePrefix.getText());
                if (!isBlank(ignoreTable.getText()))
                    properties.setIgnoreTable(ignoreTable.getText());
                generateBuild.build(finalSql, properties);
                finalSql.commitTransaction();
                ToastUtil.toast("实体生成成功", selectDir.getScene().getWindow());
            } catch (Exception e) {
                showError(e);
                e.printStackTrace();
            } finally {
                if (finalSql != null && finalSql.getConnection() != null && selectedIndex != 2)
                    try {
                        finalSql.getConnection().close();
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                // 存储配置
                storeProperties();
            }
        });
    }

    private void storeProperties() {
        try {
            if (url.getText() != null)
                conf.setProperty("url", url.getText());
            if (username.getText() != null)
                conf.setProperty("username", username.getText());
            if (password.getText() != null)
                conf.setProperty("password", password.getText());
            if (ignoreTablePrefix.getText() != null)
                conf.setProperty("ignoreTablePrefix", ignoreTablePrefix.getText());
            if (cover != null)
                conf.setProperty("cover", cover.isSelected() ? "true" : "false");
            if (ignoreTable.getText() != null)
                conf.setProperty("ignoreTable", ignoreTable.getText());
            conf.store(new FileOutputStream(file), "commit");
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }

    private FinalSql getFinalSql() {
        FinalSqlDevDataSource dataSource = new FinalSqlDevDataSource(
                driverName.getSelectionModel().getSelectedItem(),
                isBlank(url.getText()) ? url.getPromptText() : url.getText(),
                isBlank(username.getText()) ? username.getPromptText() : username.getText(),
                isBlank(password.getText()) ? password.getPromptText() : password.getText()
        );

        SqlConfig sqlConfig = new SqlConfig(dataSource);
        sqlConfig.setShowLog(true);
        return new FinalSqlManage(sqlConfig);
    }

    private boolean isBlank(String str) {
        return str == null || str.length() == 0;
    }

    private void showError(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        String exceptionText = sw.toString();

        Stage stage = new Stage();
        stage.initOwner(build.getScene().getWindow());
        stage.initModality(Modality.APPLICATION_MODAL);
        stage.setTitle("出现异常");
        stage.setMinWidth(500);
        stage.setMinHeight(360);
        stage.setScene(new Scene(new TextArea(exceptionText)));
        stage.show();
    }
}
